home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / examples / insight / plugins / mydat.pro < prev    next >
Text File  |  1997-07-08  |  29KB  |  850 lines

  1. ; $Id: mydat.pro,v 1.13 1997/03/28 17:08:14 billo Exp $
  2. ;
  3. ; Copyright (c) 1997, Research Systems, Inc.  All rights reserved.
  4. ;   Unauthorized reproduction prohibited.
  5. ;+
  6. ; FILE:
  7. ;       mydat.pro
  8. ;
  9. ; PURPOSE:
  10. ;       This file contains a File PlugIn that reads the .dat files
  11. ;       in the examples directory of the IDL distribution. It can also
  12. ;       be used to read other structured binary files.
  13. ;
  14. ; CONTENTS:
  15. ;       CALLBACK ROUTINES
  16. ;           pro WriteMydat      - writes a structured binary file
  17. ;           pro ReadMydat       - reads a structured binary file
  18. ;           dat_CheckDataDir    - Checks for file in the example/data directory
  19. ;           dat_BuildType       - Builds data for the READU routine.
  20. ;           dat_Verify          - Verifys user input into the dialog.
  21. ;           dat_ComputeFields   - Computes the field values when others change
  22. ;           dat_HandleEvents    - Handles dialog events
  23. ;           dat_PromptUser      - Builds and displays the dialog
  24. ;
  25. ;       REGISTRATION FUNCTION
  26. ;           fun Mydat           - registers the PlugIn
  27. ;
  28. ;-
  29.  
  30. ; *****************************************************************************
  31. ;       CALLBACK ROUTINES
  32. ; *****************************************************************************
  33.  
  34. ; -----------------------------------------------------------------------------
  35. ;
  36. ;   Purpose:  Check to see if the file is in the EXAMPLE/DATA directory. If so,
  37. ;            get the information about it needed to read it in.
  38. ;
  39. function dat_CheckDataDir, $
  40.     filename, $                     ; IN: name of file to read
  41.     fileTail, $                     ; IN: name of file minus directory
  42.     DESCRIPTION=description, $      ; OUT: the description of the data read
  43.     DIMENSIONS=dimensions, $        ; OUT: the dimensions of the data read
  44.     CLASSIFICATION=classification, $; OUT: the classification of the data read
  45.     FIRST_DATA_ITEM=firstDataItem, $; OUT: the first element to read
  46.     LAST_DATA_ITEM=lastDataItem     ; OUT: the last element to read.
  47.  
  48.     name = ''
  49.     dims = LONARR(3)
  50.     desc = ''
  51.     delimiter = ''
  52.     numfiles = 0L
  53.     fileFound = 0B
  54.  
  55.     ;  Look for the file, and set up the data array and data name.
  56.     ;
  57.     OPENR, unit, FILEPATH("data.txt", SUBDIRECTORY=['examples', 'data']), $
  58.          /GET_LUN
  59.  
  60.     READF, unit, numfiles
  61.  
  62.     if (numfiles gt 0) then begin
  63.  
  64.         for nameindex = 0, numfiles - 1 do begin
  65.  
  66.             READF, unit, name, dims, desc, delimiter
  67.  
  68.             if (name eq fileTail) then begin
  69.                 fileFound = 1B
  70.                 dimensions = dims
  71.                 description = desc
  72.                 firstDataItem = 0
  73.                 lastDataItem = 0
  74.                 dimIndexes = WHERE(dimensions gt 1, dimCount)
  75.                 if (dimCount eq 1) then begin
  76.                     classification = 'Vector'
  77.                     dimensions[1:2] = 0
  78.                 endif else begin
  79.                     classification = 'Indexed Image'
  80.                     if (dimCount ge 2) then begin
  81.                         lastDataItem = dimensions[2]-1
  82.                         dimensions[2] = 0
  83.                     endif
  84.                 endelse
  85.  
  86.                 goto, FILE_FOUND
  87.             endif
  88.  
  89.             if (delimiter ne '*') then $
  90.                MESSAGE, "* delimiter not found in data.txt"
  91.  
  92.         endfor
  93.     endif
  94.  
  95.   FILE_FOUND:
  96.  
  97.     FREE_LUN, unit
  98.  
  99.     return, fileFound
  100. end
  101.  
  102. ; -----------------------------------------------------------------------------
  103. ;
  104. ;   Purpose: Create the data to serve as the container for the READU routine.
  105. ;
  106. function dat_BuildType, $
  107.     type, $     ; IN: IDL data type of data to create.
  108.     dimSizes    ; IN: Vector of sizes for each dimension.
  109.                 ; RESULT: Data to serve as container for READU routine.
  110.  
  111.     index = WHERE(dimSizes gt 0, nDims)
  112.  
  113.     ; Array Value
  114.     ;
  115.     if (nDims gt 0) then begin
  116.  
  117.         ; Build up a size array for making the array
  118.         sizeArray = LONARR(3+nDims)
  119.  
  120.         nElts = 1
  121.         for i=0, nDims-1 do $
  122.             nElts = dimSizes[i] * nElts
  123.  
  124.         sizeArray[0] = nDims
  125.         sizeArray[1:nDims] = dimSizes[0:nDims-1]
  126.         sizeArray[nDims+1] = type
  127.         sizeArray[nDims+2] = nElts
  128.  
  129.         value = MAKE_ARRAY(SIZE=sizeArray)
  130.  
  131.     ; Scalar
  132.     ;
  133.     endif else begin
  134.  
  135.         case (type) of
  136.             0:  Value   = 0     ;; Can't return undef but undef is OK.
  137.             1:  Value   = 0B
  138.             2:  Value   = 0
  139.             3:  Value   = 0L
  140.             4:  Value   = 0.0
  141.             5:  Value   = 0.0D
  142.             6:  Value   = COMPLEX(0)
  143.             7:  Value   = ''
  144.             9:  Value   = DCOMPLEX(0)
  145.             else:
  146.  
  147.         endcase
  148.  
  149.     endelse
  150.  
  151.     RETURN, value
  152.  
  153. end
  154.  
  155. ; -----------------------------------------------------------------------------
  156. ;
  157. ;   Purpose: Verify what was entered into the dialog is correct.
  158. ;
  159. function dat_Verify, $
  160.     psState ; IN: Pointer to structure of widget ids and values.
  161.             ; RESULT: 1B for success. Will throw errors (unsuccessful).
  162.  
  163.     ;  Get base name of data item.
  164.     ;
  165.     WIDGET_CONTROL, (*psState).wNameText, GET_VALUE=dataName
  166.     (*psState).name = dataName[0]
  167.  
  168.     ;  Get the description of data.
  169.     ;
  170.     WIDGET_CONTROL, (*psState).wDescriptionText, GET_VALUE=description
  171.     (*psState).description = description[0]
  172.  
  173.     ;  Get starting byte offset into the file.
  174.     ;
  175.     WIDGET_CONTROL, (*psState).wOffsetText, GET_VALUE=offset
  176.     offset = LONG(offset[0])
  177.     if ((offset ge (*psState).fileSize) or (offset lt 0)) then $
  178.         MESSAGE,'The "offset" must be greater than or equal to zero and'+ $
  179.             ' less than to the file size ('+$
  180.             STRING((*psState).fileSize, FORMAT='(I0)')+') in bytes.' $
  181.     else $
  182.         (*psState).offset = offset
  183.  
  184.     ;  Get IDL data type.
  185.     ;
  186.     dataTypeIndex = WIDGET_INFO((*psState).wTypeList, /DROPLIST_SELECT)
  187.     (*psState).dataTypeIndex = dataTypeIndex
  188.  
  189.     ;  Get the classification.
  190.     ;
  191.     classIndex = WIDGET_INFO((*psState).wClassList, /DROPLIST_SELECT)
  192.     (*psState).classIndex = classIndex
  193.  
  194.     ;  Get starting data element.
  195.     ;
  196.     WIDGET_CONTROL, (*psState).wFirstDataItemText, GET_VALUE=first
  197.     (*psState).firstDataItem = LONG(first[0])
  198.  
  199.     ;  Get ending data element.
  200.     ;
  201.     WIDGET_CONTROL, (*psState).wLastDataItemText, GET_VALUE=last
  202.     (*psState).lastDataItem = LONG(last[0])
  203.  
  204.     if ((*psState).firstDataItem gt (*psState).lastDataItem) then $
  205.         MESSAGE,'The "From" index must be less than or equal to the "To" index'
  206.  
  207.     ;  Get dimension sizes.
  208.     ;
  209.     for seqDim = 0, 7 do begin
  210.         WIDGET_CONTROL, (*psState).wSizeText[seqDim], GET_VALUE=dimSize
  211.         (*psState).dimensions[seqDim] = LONG(dimSize[0])
  212.     endfor
  213.  
  214.     ; Create the empty data (actually a pointer to it) to READU into.
  215.     ;
  216.     (*psState).pData = $
  217.         PTR_NEW(dat_BuildType((*psState).dataTypes[dataTypeIndex], $
  218.         (*psState).dimensions))
  219.  
  220.     ; If reached this point, return success
  221.     ;
  222.     RETURN, 1B
  223.  
  224. end
  225.  
  226. ; -----------------------------------------------------------------------------
  227. ;
  228. ;   Purpose: Return the number of bytes for the IDL data type.
  229. ;
  230. function dat_SizeOf, type
  231.  
  232.     ;  Get the number of bytes per element.
  233.     ;
  234.     case (type) of
  235.  
  236.         1: nBytes = 1L              ; Byte
  237.         2: nBytes = 2L              ; Int
  238.         3: nBytes = 4L              ; Long
  239.         4: nBytes = 4L              ; Float
  240.         5: nBytes = 8L              ; Double
  241.         6: nBytes = 8L              ; Complex
  242.         9: nBytes = 16L             ; Double Complex
  243.  
  244.         else: MESSAGE, 'Unsupported IDL data type.'
  245.     endcase
  246.  
  247.     return, nBytes
  248. end
  249.  
  250. ; -----------------------------------------------------------------------------
  251. ;
  252. ;   Purpose: Recompute field values when something changes in the dialog.
  253. ;
  254. pro dat_ComputeFields, psState, $
  255.     SET_FROM_TO=setFromTo, $ ; IN: true if need to compute From and To fields.
  256.     SET_LEFTOVER=setLeftOver ; IN: true if only need to compute LeftOver field.
  257.  
  258.     if (dat_Verify(psState)) then begin
  259.  
  260.         ;  Get the number of bytes per element.
  261.         ;
  262.         nBytes = dat_SizeOf((*psState).dataTypes[(*psState).dataTypeIndex])
  263.  
  264.         ; Compute the file size based on the starting offset into the file.
  265.         ;
  266.         newSize = (*psState).fileSize - (*psState).offset
  267.  
  268.         ; Compute the number of elements in the file based on the size of
  269.         ; the data type.
  270.         ;
  271.         numElements = newSize / nBytes
  272.  
  273.         ; Take the root to guess at square dimensions
  274.         ;
  275.         numDims = (*psState).numDimensions[(*psState).classIndex]
  276.  
  277.         ; Deal with true color image formats specially.
  278.         ;
  279.         case (*psState).classNames[(*psState).classIndex] of
  280.  
  281.             'Pixel Interleaved Image': begin
  282.                 numElements = numElements / 3
  283.                 dims = numElements ^ (1./2)
  284.                 dimensions = [3, dims, dims, 0,0,0,0,0]
  285.             end
  286.             'Line Interleaved Image': begin
  287.                 numElements = numElements / 3
  288.                 dims = numElements ^ (1./2)
  289.                 dimensions = [dims, 3, dims, 0,0,0,0,0]
  290.             end
  291.             'Image Interleaved Image': begin
  292.                 numElements = numElements / 3
  293.                 dims = numElements ^ (1./2)
  294.                 dimensions = [dims, dims, 3, 0,0,0,0,0]
  295.             end
  296.             else: begin
  297.                 dims = numElements ^ (1./numDims)
  298.  
  299.                 dimensions = LONARR(8)
  300.                 if (numDims gt 0) then $
  301.                     dimensions[0:numDims-1] = dims
  302.             end
  303.         endcase
  304.  
  305.         ; The From and To fields need to be computed when the user
  306.         ; changes the values in the dimensions fields.
  307.         ;
  308.         if (KEYWORD_SET(setFromTo)) then begin
  309.  
  310.             elementsPerData = 1
  311.             for seqDim = 0, numDims-1 do begin
  312.                 if ((*psState).dimensions[seqDim] lt 0) then $
  313.                     MESSAGE,'Dimensions must be greater than zero.' $
  314.                 else $
  315.                     elementsPerData = $
  316.                         (*psState).dimensions[seqDim] * elementsPerData
  317.             endfor
  318.  
  319.             (*psState).firstDataItem = 0
  320.             (*psState).lastDataItem = LONG(numElements/elementsPerData)
  321.  
  322.             if ((*psState).lastDataItem gt 0) then $
  323.                 (*psState).lastDataItem = (*psState).lastDataItem - 1
  324.  
  325.             WIDGET_CONTROL, (*psState).wFirstDataItemText, SET_VALUE='0'
  326.             WIDGET_CONTROL, (*psState).wLastDataItemText, $
  327.                 SET_VALUE=STRING((*psState).lastDataItem, FORMAT='(I0)')
  328.  
  329.             leftover = newSize - $
  330.                 ((((*psState).lastDataItem - (*psState).firstDataItem + 1) * $
  331.                 elementsPerData) * nBytes)
  332.  
  333.         endif else if (KEYWORD_SET(setLeftOver)) then begin
  334.  
  335.             ; Only need to compute the leftover bytes when the user edits
  336.             ; the From or To fields.
  337.             ;
  338.             elementsPerData = 1
  339.             for seqDim = 0, numDims-1 do begin
  340.                 elementsPerData = $
  341.                         (*psState).dimensions[seqDim] * elementsPerData
  342.             endfor
  343.  
  344.             leftover = newSize - $
  345.                 ((((*psState).lastDataItem - (*psState).firstDataItem + 1) * $
  346.                 elementsPerData) * nBytes)
  347.  
  348.         endif else begin
  349.  
  350.             ; Compute the dimensions if the offset, data type or classification
  351.             ; fields are changed by the user.
  352.             ;
  353.             elementsPerData = 1
  354.             for seqDim = 0, 7 do $
  355.                 if (seqDim lt numDims) then begin
  356.                     WIDGET_CONTROL, (*psState).wSizeText[seqDim], $
  357.                         SET_VALUE=STRING(dimensions[seqDim], FORMAT='(I0)'), $
  358.                         /SENSITIVE
  359.                     elementsPerData = dimensions[seqDim] * elementsPerData
  360.                 endif else $
  361.                     WIDGET_CONTROL, (*psState).wSizeText[seqDim], $
  362.                         SET_VALUE='', SENSITIVE=0
  363.             WIDGET_CONTROL, (*psState).wFirstDataItemText, SET_VALUE='0'
  364.             WIDGET_CONTROL, (*psState).wLastDataItemText, SET_VALUE='0'
  365.  
  366.             leftover = newSize - (elementsPerData * nBytes)
  367.  
  368.         endelse
  369.  
  370.         ; Specify what classification of data the user is setting the
  371.         ; From and To fields for.
  372.         ;
  373.         WIDGET_CONTROL, (*psState).wClassLabel, $
  374.             SET_VALUE='('+(*psState).classNames[(*psState).classIndex]+'s)'
  375.  
  376.         ; If the fields represent an exact fit with the file, display nothing.
  377.         ;
  378.         if (leftover eq 0) then $
  379.             WIDGET_CONTROL, (*psState).wLeftOverLabel, SET_VALUE='' $
  380.         else if (leftover gt 0) then $
  381.  
  382.             ; If the user has specified a format the comes up short of fitting
  383.             ; the file, indicate how many bytes short that they are.
  384.             ;
  385.             WIDGET_CONTROL, (*psState).wLeftOverLabel, SET_VALUE='( '+$
  386.                 STRING(leftover, FORMAT='(I0)') + ' bytes short of EOF)' $
  387.         else $
  388.  
  389.             ; If the user has specified a format the goes past the end-of-file,
  390.             ; indicate how many bytes past the EOF that they are.
  391.             ;
  392.             WIDGET_CONTROL, (*psState).wLeftOverLabel, SET_VALUE='( '+$
  393.                 STRING((-1)*leftover, FORMAT='(I0)') + ' bytes past EOF)'
  394.     endif
  395. end
  396.  
  397. ; -----------------------------------------------------------------------------
  398. ;
  399. ;   Purpose: Handle events for the dialog.
  400. ;
  401. pro dat_HandleEvents, sEvent
  402.  
  403.     ;  Grab the state pointer from the widget user value.
  404.     ;
  405.     WIDGET_CONTROL, sEvent.top, GET_UVALUE=psState
  406.  
  407.     ;  Catch errors and display them in a dialog.
  408.     ;
  409.     CATCH, error
  410.     if (error ne 0) then begin
  411.         CATCH, /CANCEL
  412.         void = DIALOG_MESSAGE(!ERR_STRING, DIALOG_PARENT=(*psState).wMainBase)
  413.         RETURN
  414.     endif
  415.  
  416.     case (sEvent.id) of
  417.  
  418.         (*psState).wOKButton: $
  419.  
  420.             if (dat_Verify(psState)) then begin
  421.                 ;  Set and return success flag.
  422.                 ;
  423.                 (*psState).update = 1
  424.  
  425.                 WIDGET_CONTROL, sEvent.top, /DESTROY
  426.             endif
  427.  
  428.         (*psState).wCancelButton: WIDGET_CONTROL, sEvent.top, /DESTROY
  429.  
  430.         (*psState).wSizeText[0]: dat_ComputeFields, psState, /SET_FROM_TO
  431.         (*psState).wSizeText[1]: dat_ComputeFields, psState, /SET_FROM_TO
  432.         (*psState).wSizeText[2]: dat_ComputeFields, psState, /SET_FROM_TO
  433.         (*psState).wSizeText[3]: dat_ComputeFields, psState, /SET_FROM_TO
  434.         (*psState).wSizeText[4]: dat_ComputeFields, psState, /SET_FROM_TO
  435.         (*psState).wSizeText[5]: dat_ComputeFields, psState, /SET_FROM_TO
  436.         (*psState).wSizeText[6]: dat_ComputeFields, psState, /SET_FROM_TO
  437.         (*psState).wSizeText[7]: dat_ComputeFields, psState, /SET_FROM_TO
  438.  
  439.         (*psState).wFirstDataItemText: dat_ComputeFields, psState, $
  440.             /SET_LEFTOVER
  441.         (*psState).wLastDataItemText: dat_ComputeFields, psState, $
  442.             /SET_LEFTOVER
  443.  
  444.         else: dat_ComputeFields, psState
  445.  
  446.     endcase
  447.  
  448. end
  449.  
  450. ; -----------------------------------------------------------------------------
  451. ;
  452. ;   Purpose: Create and display the dialog.
  453. ;
  454. function dat_PromptUser, $
  455.     fileName, $                     ; IN: Full file name to read in
  456.     fileSize, $                     ; IN: Size in bytes of the file
  457.     DESCRIPTION=description, $      ; IN/OUT: Description of data
  458.     DIMENSIONS=dimensions, $        ; IN/OUT: Dimensions (from example/data)
  459.     OFFSET=offset, $                ; IN/OUT: Starting byte of reading
  460.     NAME=name, $                    ; IN/OUT: Name to use for data
  461.     KNOWN_FILE=knownFile, $         ; IN: True if from example/data directory
  462.     GROUP=wGroup, $                 ; IN: Parent for dialog
  463.     DATA=data, $                    ; OUT: Data to read into.
  464.     TYPE=type, $                    ; OUT: Type of data to read.
  465.     CLASSIFICATION=classification, $; IN/OUT: Classification of data.
  466.     FIRST_DATA_ITEM=firstDataItem, $; IN/OUT: First data item to read
  467.     LAST_DATA_ITEM=lastDataItem, $  ; IN/OUT: through last item to read
  468.     IMAGE=image                     ; OUT: True if an image
  469.  
  470.     ;  Type of data
  471.     ;
  472.     typeNames = ['Byte', 'Integer', 'Long Integer', 'Float', $
  473.         'Double Float', 'Complex', 'Double Complex']
  474.     dataTypes = [1,2,3,4,5,6,9] ; Corresponding SIZE() type values
  475.     dataTypeIndex = 0 ; default to Byte (index 0).
  476.  
  477.     ; Classification
  478.     ;
  479.     classNames = ['Scalar', 'Vector', '2D Array', '3D Array', $
  480.         '4D Array', '5D Array', '6D Array', '7D Array', '8D Array', $
  481.         'Indexed Image', 'Pixel Interleaved Image', $
  482.         'Line Interleaved Image', 'Image Interleaved Image']
  483.     numDimensions = [0,1,2,3,4,5,6,7,8,2,3,3,3]
  484.  
  485.     ; Initialize values if they weren't passed in.
  486.     ;
  487.     if (N_ELEMENTS(offset) eq 0) then $
  488.         offset = 0
  489.  
  490.     if (N_ELEMENTS(firstDataItem) eq 0) then $
  491.         firstDataItem = 0
  492.     if (N_ELEMENTS(lastDataItem) eq 0) then $
  493.         lastDataItem = 0
  494.     if (N_ELEMENTS(description) eq 0) then $
  495.         description = ''
  496.  
  497.     nDims = N_ELEMENTS(dimensions)
  498.     if (nDims eq 0) then $
  499.         dimensions = LONARR(8) $
  500.     else begin
  501.         dimensions = [dimensions, LONARR(8-nDims)]
  502.     endelse
  503.  
  504.     if (N_ELEMENTS(classification) ne 0) then $
  505.         classTypeIndex = (WHERE(classNames eq classification, classCount))[0] $
  506.     else begin
  507.         dimIndexes = WHERE(dimensions gt 0, nDims)
  508.  
  509.         if ((nDims eq 2) or (nDims eq 0)) then $
  510.             classTypeIndex = 9 $ ; Default 0D and 2D to type Image (index 9).
  511.         else $
  512.             classTypeIndex = nDims
  513.  
  514.         classification = classNames[classTypeIndex]
  515.     endelse
  516.  
  517.     ;  Create main base (non-sizable).
  518.     ;
  519.     wMainBase = WIDGET_BASE(/COLUMN, TITLE='Structured Binary File', /MODAL, $
  520.         GROUP_LEADER=wGroup)
  521.  
  522.     wTopBase = WIDGET_BASE(wMainBase, /COLUMN)
  523.  
  524.     ;  Define base for format information.
  525.     ;
  526.     wControlBase = WIDGET_BASE(wMainBase, /COLUMN, /FRAME, /BASE_ALIGN_LEFT)
  527.  
  528.     ;  Define base for action buttons.
  529.     ;
  530.     wActionBase = WIDGET_BASE(wMainBase, /ROW, /ALIGN_CENTER)
  531.  
  532.     ; ----------------------
  533.     ;    Input Parameters
  534.     ; ----------------------
  535.  
  536.     ;  Name of data
  537.     ;
  538.     wRowBase = WIDGET_BASE(wTopBase, /ROW, XPAD=0, YPAD=0, $
  539.         /BASE_ALIGN_CENTER)
  540.     void = WIDGET_LABEL(wRowBase, VALUE='Data Name:', /ALIGN_LEFT)
  541.     wNameText = WIDGET_TEXT(wRowBase, VALUE=name, /EDITABLE, XSIZE=40)
  542.  
  543.     ;  Description of data
  544.     ;
  545.     wRowBase = WIDGET_BASE(wTopBase, /ROW, XPAD=0, YPAD=0, $
  546.         /BASE_ALIGN_CENTER)
  547.     void = WIDGET_LABEL(wRowBase, VALUE='Description:', /ALIGN_LEFT)
  548.     wDescriptionText = WIDGET_TEXT(wRowBase, VALUE=description, $
  549.         /EDITABLE, XSIZE=40)
  550.  
  551.     ;  Informative description of steps to follow
  552.     ;
  553.     void = WIDGET_LABEL(wControlBase, $
  554.         VALUE="Please set the following fields in the indicated order.", $
  555.         /ALIGN_LEFT)
  556.  
  557.     ;  Offset into the file
  558.     ;
  559.     wOffsetBase = WIDGET_BASE(wControlBase, /ROW, XPAD=0, YPAD=0, $
  560.         /BASE_ALIGN_CENTER)
  561.     wOffsetLabel = WIDGET_LABEL(wOffsetBase, $
  562.         VALUE="Step 1: Enter Starting Byte Offset:", $
  563.         /ALIGN_LEFT)
  564.     wOffsetText = WIDGET_TEXT(wOffsetBase, /EDITABLE, XSIZE=5, $
  565.         VALUE=STRING(offset, FORMAT='(I0)'), /ALL_EVENTS)
  566.  
  567.     ;  IDL data type
  568.     ;
  569.     wTypeList = WIDGET_DROPLIST(wControlBase, VALUE=typeNames, $
  570.         TITLE='Step 2: Select Data Type:')
  571.     WIDGET_CONTROL, wTypeList, SET_DROPLIST_SELECT=dataTypeIndex
  572.  
  573.     ; Classification
  574.     ;
  575.     wClassList = WIDGET_DROPLIST(wControlBase, VALUE=classNames, $
  576.         TITLE='Step 3: Select Classification:')
  577.     WIDGET_CONTROL, wClassList, SET_DROPLIST_SELECT=classTypeIndex
  578.  
  579.     ;  Dimensions of data
  580.     ;
  581.     wDimLabel = WIDGET_LABEL(wControlBase, $
  582.         VALUE="Step 4: Enter Dimensions:", /ALIGN_LEFT)
  583.     wDimBase = WIDGET_BASE(wControlBase, /ROW, SPACE=0, XPAD=0, YPAD=0)
  584.     wSizeText = LONARR(8)
  585.     for seqDim = 0, 7 do begin
  586.         if (dimensions[seqDim] eq 0) then $
  587.             dimString = '' $
  588.         else $
  589.             dimString = STRING(dimensions[seqDim], FORMAT='(I0)')
  590.         wSizeText[seqDim] = WIDGET_TEXT(wDimBase, XSIZE=7, /EDITABLE, $
  591.             VALUE=dimString, /ALL_EVENTS)
  592.     endfor
  593.  
  594.     ;  First through last data item to read
  595.     ;
  596.     wElementBase = WIDGET_BASE(wControlBase, /ROW, XPAD=0, YPAD=0, $
  597.         /BASE_ALIGN_CENTER)
  598.     void = WIDGET_LABEL(wElementBase, VALUE='Step 5: From:', /ALIGN_LEFT)
  599.     wFirstDataItemText = WIDGET_TEXT(wElementBase, /EDITABLE, XSIZE=5, $
  600.         VALUE=STRING(firstDataItem, FORMAT='(I0)'), /ALL_EVENTS)
  601.     void = WIDGET_LABEL(wElementBase, VALUE='To:', /ALIGN_LEFT)
  602.     wLastDataItemText = WIDGET_TEXT(wElementBase, /EDITABLE, XSIZE=5, $
  603.         VALUE=STRING(lastDataItem, FORMAT='(I0)'), /ALL_EVENTS)
  604.     wClassLabel = WIDGET_LABEL(wElementBase, VALUE='('+classification+'s)', $
  605.         /DYNAMIC_RESIZE, /ALIGN_LEFT)
  606.  
  607.     ; A notice to specify how many bytes are left over
  608.     ;
  609.     wLeftOverLabel = WIDGET_LABEL(wControlBase, /ALIGN_LEFT, VALUE='', $
  610.         /DYNAMIC_RESIZE)
  611.  
  612.     ; ----------------------
  613.     ;    Action Buttons
  614.     ; ----------------------
  615.  
  616.     padding = ' '
  617.     wOKButton     = WIDGET_BUTTON(wActionBase, VALUE='   OK   ')
  618.     void          = WIDGET_LABEL(wActionBase, VALUE=padding)
  619.     void          = WIDGET_LABEL(wActionBase, VALUE=padding)
  620.     wCancelButton = WIDGET_BUTTON(wActionBase, VALUE=' Cancel ')
  621.  
  622.     psState = PTR_NEW ({ $
  623.         update: 0, $
  624.         offset: offset, $
  625.         dimensions: dimensions, $
  626.         description: description, $
  627.         name: name, $
  628.         dataTypeIndex: dataTypeIndex, $
  629.         fileSize: fileSize, $
  630.         dataTypes: dataTypes, $
  631.         numDimensions: numDimensions, $
  632.         firstDataItem:firstDataItem, $
  633.         lastDataItem: lastDataItem, $
  634.         classIndex: classTypeIndex, $
  635.         classNames: classNames, $
  636.         pData: PTR_NEW(), $
  637.         knownFile: knownFile, $
  638.         wMainBase: wMainBase, $
  639.         wClassList: wClassList, $
  640.         wFirstDataItemText: wFirstDataItemText, $
  641.         wLastDataItemText: wLastDataItemText, $
  642.         wTypeList: wTypeList, $
  643.         wSizeText: wSizeText, $
  644.         wNameText: wNameText,$
  645.         wDescriptionText: wDescriptionText,$
  646.         wOffsetText: wOffsetText,$
  647.         wClassLabel: wClassLabel, $
  648.         wLeftOverLabel: wLeftOverLabel, $
  649.         wOKButton: wOKButton, $
  650.         wCancelButton: wCancelButton $
  651.         })
  652.  
  653.     if (knownFile) then begin
  654.         WIDGET_CONTROL, wOffsetLabel, SENSITIVE=0
  655.         WIDGET_CONTROL, wOffsetText, SENSITIVE=0
  656.         WIDGET_CONTROL, wTypeList, SENSITIVE=0
  657.         WIDGET_CONTROL, wClassList, SENSITIVE=0
  658.         WIDGET_CONTROL, wDimLabel, SENSITIVE=0
  659.         for seqDim = 0, 7 do $
  660.             WIDGET_CONTROL, wSizeText[seqDim], SENSITIVE=0
  661.     endif else $
  662.         dat_ComputeFields, psState
  663.  
  664.     WIDGET_CONTROL, wMainBase, SET_UVALUE=psState
  665.     WIDGET_CONTROL, wMainBase, /REALIZE
  666.  
  667.     ;  Start event loop.
  668.     ;
  669.     WIDGET_CONTROL, wMainBase, DEFAULT_BUTTON=wOKButton, $
  670.         CANCEL_BUTTON=wCancelButton
  671.  
  672.     XMANAGER, 'dat_PromptUser', wMainBase, EVENT_HANDLER='dat_HandleEvents'
  673.  
  674.     update = (*psState).update
  675.  
  676.     ; If the user chose the OK button and no errors were found, copy the
  677.     ; field values into the output keywords.
  678.     ;
  679.     if (update) then begin
  680.         description = (*psState).description
  681.         data = (*(*psState).pData)
  682.         dimensions = (*psState).dimensions
  683.         offset = (*psState).offset
  684.         name = (*psState).name
  685.         description = (*psState).description
  686.         firstDataItem = (*psState).firstDataItem
  687.         lastDataItem = (*psState).lastDataItem
  688.         classification = classNames[(*psState).classIndex]
  689.         image = (classification eq 'Indexed Image' or $
  690.                  classification eq 'Pixel Interleaved Image' or $
  691.                  classification eq 'Line Interleaved Image' or $
  692.                  classification eq 'Image Interleaved Image')
  693.         type = dataTypes[(*psState).dataTypeIndex]
  694.     endif
  695.  
  696.     PTR_FREE, (*psState).pData
  697.     PTR_FREE, psState
  698.  
  699.     RETURN, update
  700.  
  701. end
  702.  
  703. ; -----------------------------------------------------------------------------
  704. ;
  705. ;    Purpose:  File PlugIn Read Routine.
  706. ;
  707. pro ReadMydat, $
  708.     filename, $             ; IN: name of file to read
  709.     dataName, $             ; IN: default data name
  710.     TAIL=fileNameTail, $    ; IN: filename minus the directory name
  711.     GROUP=wGroup, $         ; IN: parent base for any dialogs created
  712.     _EXTRA=extra            ; IN: information to pass to INSPUT
  713.  
  714.     ;  Put up wait cursor.
  715.     ;
  716.     WIDGET_CONTROL, /HOURGLASS
  717.  
  718.     ;  If the file is in the example/data directory get its dimensions and
  719.     ;  description.
  720.     ;
  721.     exampleFile = dat_CheckDataDir(filename, fileNameTail, $
  722.         DESCRIPTION=description, $
  723.         DIMENSIONS=dimensions, CLASSIFICATION=classification, $
  724.         FIRST_DATA_ITEM=firstDataItem, LAST_DATA_ITEM=lastDataItem)
  725.  
  726.     ;  Open the file.
  727.     ;
  728.     OPENR, unit, filename, /GET_LUN, /BLOCK, ERROR=ierror
  729.  
  730.     if (ierror ne 0) then $
  731.         MESSAGE, 'Error occured opening file "' + filename + $
  732.             '".', /NONAME
  733.  
  734.     ; Get the file info to determine its size.
  735.     ;
  736.     sFstat = FSTAT(unit)
  737.  
  738.     ; Ask the user (via a dialog) for more information.
  739.     ;
  740.     if (dat_PromptUser(fileName, sFstat.size, DESCRIPTION=description, $
  741.         DIMENSIONS=dimensions, OFFSET=offset, NAME=dataName, DATA=data, $
  742.         FIRST_DATA_ITEM=firstDataItem, LAST_DATA_ITEM=lastDataItem, $
  743.         GROUP=wGroup, CLASSIFICATION=classification, TYPE=type, $
  744.         KNOWN_FILE=exampleFile, IMAGE=isImage)) then begin
  745.  
  746.         nSkippedBytes = dat_SizeOf(type) * N_ELEMENTS(data) * firstDataItem
  747.  
  748.         ; Skip ahead in the file to the desired offset.
  749.         ;
  750.         POINT_LUN, unit, offset+nSkippedBytes
  751.  
  752.         ; For each data item requested, read the file.
  753.         ;
  754.         for dIndex = firstDataItem, lastDataItem do begin
  755.  
  756.             READU, unit, data
  757.  
  758.             sDataElement = CREATE_STRUCT(STRING(dIndex), data)
  759.  
  760.             ; Skip if not yet the first data item.
  761.             ;
  762.             if (dIndex eq firstDataItem) then $
  763.                 sData = sDataElement $
  764.             else $
  765.                 sData = CREATE_STRUCT(sData, sDataElement)
  766.         endfor
  767.  
  768.         if (N_ELEMENTS(sData) ne 0) then $
  769.             ;  Put all the data into the Data Manager.
  770.             ;
  771.             INSPUT, $
  772.                 sData, $                   ; the data to put
  773.                 NAME=dataName, $           ; the name to give it
  774.                 DESCRIPTION=description, $ ; the data description
  775.                 IMAGE=isImage, $           ; Set if image class
  776.                 GROUP=wGroup, $            ; parent for dialogs
  777.                 REPLACE=2, $               ; 2 = prompt if data name
  778.                                            ;  not unique.
  779.                 _EXTRA=extra               ; extra information
  780.  
  781.     endif
  782.  
  783.     ; Close the file and free the unit
  784.     ;
  785.     FREE_LUN, unit
  786.  
  787. end
  788.  
  789. ; -----------------------------------------------------------------------------
  790. ;
  791. ;    Purpose:  File PlugIn Write Routine.
  792. ;
  793. pro WriteMydat, $
  794.     filename, $         ; IN: name of file to write to
  795.     dataName, $         ; IN: name of data item to write, e.g., mydata
  796.     TAIL=tail, $        ; IN: (opt) filename w/out directory, e.g., myfile.dat
  797.     GROUP=wGroup, $     ; IN: (opt) ID of widget group leader
  798.     _EXTRA=extra        ; IN: information to pass to INSGET
  799.  
  800.     ;  Get the data from the Data Manager.
  801.     ;
  802.     data = INSGET( $
  803.         dataName,   $                               ; data item to write
  804.         GROUP       = wGroup, $                     ; widget group leader
  805.         _EXTRA      = extra)                        ; extra information
  806.  
  807.     ;  Open the file.
  808.     ;
  809.     OPENW, unit, filename, /GET_LUN, /BLOCK, ERROR=ierror
  810.  
  811.     if (ierror ne 0) then $
  812.         MESSAGE, 'Error occured opening file "' + filename + $
  813.             '".', /NONAME
  814.  
  815.     WRITEU, unit, data
  816.  
  817.     ; Free the unit
  818.     ;
  819.     FREE_LUN, unit
  820.  
  821. end
  822.  
  823. ; *****************************************************************************
  824. ;       REGISTRATION FUNCTION
  825. ; *****************************************************************************
  826.  
  827. ; -----------------------------------------------------------------------------
  828. ;
  829. ;    Purpose:  Register the file PlugIn.
  830. ;
  831. function Mydat
  832.  
  833.     ;  Return the File PlugIn Registration Structure.
  834.     ;
  835.     RETURN, { $
  836.         type:       'File_PlugIn', $                ; PlugIn type
  837.         title:      'Structured Binary', $          ; PlugIn title
  838.         purpose:    'Handle .dat files.', $         ; PlugIn purpose
  839.         read_proc:  'ReadMydat', $                  ; read callback
  840.         write_proc: 'WriteMydat', $                 ; write callback
  841.         file_ext:   'dat', $                        ; extension(s) (no period)
  842.         version:    '5.0', $                        ; IDL version
  843.         revision:   '1.0' $                         ; PlugIn version
  844.         }
  845.  
  846. end
  847.  
  848. ; -----------------------------------------------------------------------------
  849.  
  850.